#include <SFML/Graphics.hpp>
#include <vector>
#include <iostream>
#include "Entities.h"
#include "Utils.h"
#include "Collision.h"
#include "Manager.h"
using namespace sf;

/** 
 * @brief Entity constructor.
 * 
 * @param Type Entity::CType of entity to construct.
 * @param Manager Reference to GameManager controlling this entity.
 * @param Position Starting position; defaults to (0, 0).
 */
Entity::Entity(CType Type, const GameManager& Manager, Vector2f Position)
		: manager(Manager)
		, position(Position)
		, uFrequency(5)
		, uSkipped(Randomizer::Random(0, uFrequency))
{
	switch (Type)
	{
		case HUMAN:
			type = PLAYER;
			break;
		case ZOMBIE:
			type = ENEMY;
			break;
		case BULLET:
			type = PROJECTILE;
			break;
		case HSTREET:
			type = WALKABLE;
			break;
		case VSTREET:
			type = WALKABLE;
			break;
        case INTERSECTION:
            type = WALKABLE;
            break;
		default:
			type = GENERIC;
			break;
	}
	Image& tImage = *manager.GetImage(type);
	sprite.SetImage(tImage);
	sprite.SetCenter(tImage.GetWidth() * 0.5f, tImage.GetHeight() * 0.5f);
	sprite.SetRotation(rotation);
	sprite.SetPosition(position);
	// load most (if not all) properties from manager config data here.
}
void Entity::Update(float FrameTime)
{
	if (uSkipped < uFrequency)
	{
		uSkipped++;
		return;
	}
	uSkipped = 0;
	if (alive)
	{
		// TODO: new collision logic.
		
		lastposition = position;
		position += velocity * FrameTime * 100.f;
		// More update logic.
	}
}
Entity::EType Entity::Type() const { return GENERIC; }

void Entity::Move(Vector2f Amount)
{
	position += Amount;
	sprite.SetPosition(position);
}

void Entity::Damage(int Amount) 
{
	health -= Amount;
	if (health <= 0)
	{
		health = 0;
		alive = false;
	}
}
Vector2f Entity::Position() const { return position; }
void Entity::Position(const Vector2f& value) { position = value; }
Vector2f Entity::Velocity() const { return velocity; }
Vector2f Entity::Scale() const { return scale; }
Vector2f Entity::Target() const { return target; }
int Entity::Health() const { return health; }
int Entity::Speed() const { return speed; }
bool Entity::Alive() const { return alive; }
Vector2f Entity::SpriteSize() const { return sprite.GetSize(); }


Projectile::Projectile(CType Type, const GameManager& Manager, Entity& Parent)
			: Entity(Type, Manager, Vector2f(-10000, -10000))
			, parent(Parent)
{
	speed = 12.f;
	alive = false;
}

EType Projectile::Type() { return PROJECTILE; }

void Projectile::Reset()
{
	position = Vector2f(-1000, -1000);
	sprite.SetPosition(position);
	velocity = Vector2f(0, 0);
	alive = false;
}

void Projectile::Fire()
{
	health = 100;
	alive = true;
	this->Target(parent->Target());
	float ang = angleTo(parent->Position(), parent->Target());
	Vector2f dir = Vector2f(cos(ang), sin(ang));
	position = parent->Position() + dir * (parent->SpriteSize().x / 2);
	velocity = dir * speed;
}

////{ ---ENTITY DEFINITIONS----------------------------------------------------------------------------------

//Entity::Entity(Image& eImage, GameManager * Manager, Vector2f Position)
//: position(Position)
//, velocity(Vector2f(0, 0))
//, rotation(0)
//, alive(true)
//, health(100)
//, speed(2.f)
//, uFrequency(5)
//, uSkipped(Randomizer::Random(0, uFrequency))
//, mobile(true)
//, manager(Manager)
//, eList(manager->Entities())
//{
    //init(eImage);
//}


//void Entity::init(Image& eImage)
//{
    //sprite.SetImage(eImage);
    //sprite.SetCenter(eImage.GetWidth() * 0.5, eImage.GetHeight() * 0.5);
    //sprite.SetPosition(position);
    //sprite.SetRotation(rotation);
//}


//void Entity::update(float frameTime)
//{
    //if (uSkipped < uFrequency)
    //{
        //uSkipped++;
        //return;
    //}
    //uSkipped = 0;
    //if (mobile)
    //{
        //for (int i = 0; i < eList->size(); i++)
        //{
            //if ((*eList)[i] == this || (*eList)[i]->Alive() == false) continue;
            //if (Collision::PixelPerfectTest(sprite, (*eList)[i]->eSprite()))
            //{
                //collision(*(*eList)[i]);
            //}
        //}
        //lastPosition = position;
        //position += velocity * frameTime * 100.f;
        //facePoint(target);
        //if (sprite.GetScale() != scale) sprite.SetScale(scale);
        //sprite.SetPosition(position);
        //sprite.SetRotation(rotation);
    //}
    //if (health <= 0)
    //{
        //alive = false;
    //}
//}

//void Entity::faceAngle(float Angle)
//{
    //rotation = Angle;
//}


//void Entity::facePoint(Vector2f Point)
//{
    //faceAngle(angleTo(position, Point) * -180 / PI);
//}


//void Entity::faceEntity(Entity& TargetEntity)
//{
    //facePoint(TargetEntity.Position());
//}


//void Entity::Move(Vector2f Direction)
//{
    //velocity += Direction;
//}


//bool Entity::isColliding(Entity& target)
//{
    //return area.Intersects(target.Area());
//}


//void Entity::collision(Entity& c)
//{
    //switch (c.Type())
    //{
        //case BULLET:
            //c.collision(*this);
            //break;
        //default: // needs revisioning to better handle spawning inside other object...
            //if (position == lastPosition)
            //{
                //float xDiff = sprite.GetCenter().x - c.eSprite().GetCenter().x;
                //float yDiff = sprite.GetCenter().y - c.eSprite().GetCenter().y;
                //if (xDiff + yDiff < 40)
                    //position -= sprite.GetSize() / 2.f;
                //position = lastPosition;
                ////position += c.eSprite().GetSize();    // attempt; runs too often and easily
            //} else position = lastPosition;
            //sprite.SetPosition(position);
            //break;
    //}
//}

//void Entity::Damage(int amount)
//{
    //health -= amount;
    //if (health <= 0)
    //{
        //health = 0;
        //alive = false;
    //}
    //sprite.SetColor(Color(255, health * 2.5, health * 2.5));
//}

//void Entity::UpdateFrequency(int Frequency)
//{
    //uFrequency = Frequency;
    //uSkipped = Randomizer::Random(0, uFrequency);
//}

//Vector2f Entity::Scale()
//{
    //return scale;
//}

//void Entity::Scale(Vector2f value)
//{
    //scale = value;
//}

//float Entity::Speed()
//{
    //return speed;
//}

//void Entity::Speed(float value)
//{
    //speed = value;
//}

//float Entity::Rotation()
//{
    //return rotation;
//}

//void Entity::Rotation(float value)
//{
    //rotation = value;
//}

//int Entity::Health()
//{
    //return health;
//}

//void Entity::Health(int value)
//{
    //health = value;
//}

//bool Entity::Alive()
//{
    //return alive;
//}

//void Entity::Alive(bool value)
//{
    //alive = value;
//}

//bool Entity::Mobile()
//{
    //return mobile;
//}

//void Entity::Mobile(bool value)
//{
    //mobile = value;
//}

//Vector2f Entity::Position()
//{
    //return position;
//}

//void Entity::Position(Vector2f value)
//{
    //position = value;
//}

//FloatRect Entity::Area()
//{
    //return area;
//}

//void Entity::Area(FloatRect value)
//{
    //area = value;
//}

//Vector2f Entity::Velocity()
//{
    //return velocity;
//}

//void Entity::Velocity(Vector2f value)
//{
    //velocity = value;
//}

//Vector2f Entity::Target()
//{
    //return target;
//}

//void Entity::Target(Vector2f value)
//{
    //target = value;
//}

//Sprite Entity::eSprite()
//{
    //return sprite;
//}

//void Entity::eSprite(Sprite value)
//{
    //sprite = value;
//}

//EType Entity::Type()
//{
    //return GENERIC;
//}
////}--------------------------------------------------------------------------------------------------------



////{ ---PLAYER DEFINITIONS----------------------------------------------------------------------------------

//Player::Player(Image& pImage, GameManager * Manager, Vector2f Position)
//: Entity(pImage, Manager, Position)
//{
    //UpdateFrequency(0);
//}

//void Player::update(float frameTime)
//{
    //Entity::update(frameTime);
    //velocity = Vector2f(0, 0);
//}


//Bullet* Player::CurrentBullet()
//{
    //return bullets[currentBullet];
//}


//void Player::collision(Entity& c)
//{
    //Entity::collision(c);
//}


//void Player::initBullets(Image & bImage)
//{
    //for (int i = 0; i < NUM_RESOURCES; i++)
    //{
		//Bullet* b = new Bullet(bImage, manager, this);
        //bullets.push_back(b);
		//manager->AddEntity(b);
    //}

    //currentBullet = 0;
//}


//std::vector<Bullet *> Player::Bullets()
//{
    //std::vector<Bullet *> returnVector;
    //for (int i = 0; i < bullets.size(); i++)
    //{
        //returnVector.push_back(bullets[i]);
    //}
    //return returnVector;
//}


//void Player::Fire()
//{
    //bullets[currentBullet]->Fire();
    //currentBullet++;
    //if (currentBullet > bullets.size() - 1) currentBullet = 0;
//}

//EType Player::Type()
//{
    //return PLAYER;
//}
////}--------------------------------------------------------------------------------------------------------



////{ ---ENEMY DEFINITIONS-----------------------------------------------------------------------------------

//Enemy::Enemy(Image& eImage, GameManager * Manager, Vector2f Position, Entity * PlayerPtr)
//: Entity(eImage, Manager, Position)
//{
    //player = PlayerPtr;
    //UpdateFrequency(0);
    //speed = 0.15f;
//}

//void Enemy::update(float frameTime)
//{
    //float angleToPlayer = angleTo(position, player->Position()); // * PI/-180;
    //target = player->Position();
    //velocity += Vector2f(cos(angleToPlayer) * speed, sin(angleToPlayer) * speed);
    //Entity::update(frameTime);
    //velocity *= 0.75f;
//}


//void Enemy::collision(Entity& c)
//{
    //if (c.Type() == PLAYER)
    //{
        //player->Damage(0);
        //velocity = Vector2f(0, 0);
    //}
    //Entity::collision(c);
//}

//EType Enemy::Type()
//{
    //return ENEMY;
//}

//Entity * Enemy::PlayerPtr()
//{
    //return player;
//}

//void Enemy::PlayerPtr(Entity * value)
//{
    //player = value;
//}

////}--------------------------------------------------------------------------------------------------------



////{ ---SCENERY DEFINITIONS---------------------------------------------------------------------------------

//Scenery::Scenery(Image& sImage, GameManager * Manager, Vector2f Position)
//: Entity(sImage, Manager, Position)
//{
    //mobile = false;
    //UpdateFrequency(25);
//}

//void Scenery::collision(Entity& c)
//{
    //Entity::collision(c);
//}

//EType Scenery::Type()
//{
    //return SCENERY;
//}
////}



////{ ---BULLET DEFINITIONS----------------------------------------------------------------------------------

//Bullet::Bullet(Image & bImage, GameManager * Manager, Entity * Parent)
//: Entity(bImage, Manager, Vector2f(-1000, -1000)),
//parent(Parent)
//{
    //speed = 12.f;
    //health = 100;
    //UpdateFrequency(0);
    //alive = false;
//}


//void Bullet::collision(Entity& c)
//{
    //if (c.Type() != SCENERY)
    //{
        //c.Velocity(c.Velocity() + velocity * 0.25f);
        //c.Damage(10);
    //}
    //Reset();
//}


//void Bullet::Reset()
//{
    //position = Vector2f(-1000, -1000);
    //sprite.SetPosition(position);
    //velocity = Vector2f(0, 0);
    //alive = false;
//}


//void Bullet::Fire()
//{
    //health = 100;
    //alive = true;
    //this->Target(parent->Target());
    //float ang = angleTo(parent->Position(), parent->Target()); // * PI/-180;
    //Vector2f dir = Vector2f(cos(ang), sin(ang));
    //position = parent->Position() + dir * (parent->eSprite().GetSize().x / 2
                                           //+ sprite.GetSize().x / 2);

    //velocity = dir * speed;
//}


//EType Bullet::Type()
//{
    //return BULLET;
//}
////}--------------------------------------------------------------------------------------------------------
